package com.ztsoft.user.service.project.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ztsoft.user.mapper.project.*;
import com.ztsoft.user.pojo.dto.ModelFileFileDTO;
import com.ztsoft.user.pojo.entity.project.*;
import com.ztsoft.user.pojo.page.PageQuery;
import com.ztsoft.user.service.project.DemandUnitService;
import com.ztsoft.user.service.project.ModelService;
import com.ztsoft.user.service.project.ProjectService;
import com.ztsoft.user.utils.Result;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.PseudoColumnUsage;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class ModelServiceImpl extends ServiceImpl<ModelMapper, PModel> implements ModelService {
    @Resource
    public ModelMapper modelMapper;
    @Resource
    public SecondBargainMapper secondBargainMapper;
    @Resource
    public ChooseMapper chooseMapper;
    @Resource
    public AgencyMapper agencyMapper;
    @Resource
    public ProjectService projectService;
    private static final String UPLOAD_DIR = "C:/dataFile/uploads/";

    @Override
    public Result<Object> list(PModel bo, PageQuery pageQuery) {
        QueryWrapper<PModel> lqw =new QueryWrapper();
        lqw.like(ObjectUtil.isNotEmpty(bo.getModelName()),"model_name",bo.getModelName());
        lqw.eq(ObjectUtil.isNotEmpty(bo.getModelType()),"model_type",bo.getModelType());
        Page<PModel> result = modelMapper.selectPage(pageQuery.build(),lqw);
        return Result.success(result);
    }

    @Override
    public Result<Object> modelOne(String id) {
        return Result.success(modelMapper.selectById(id));
    }

    @Override
    public Result<Object> add(PModel bo) {
        return Result.success(modelMapper.insert(bo));
    }

    @Override
    public Result<Object> update(PModel bo) {
        return Result.success(modelMapper.updateById(bo));
    }

    @Override
    public Result<Object> delete(String[] ids) {
        return Result.success(modelMapper.deleteBatchIds(Arrays.asList(ids)));
    }

    @Override
    public File  sendFile(ModelFileFileDTO modelFileFileDTO) {
        PModel model = modelMapper.selectById(modelFileFileDTO.getModelId());
        List<SecondBargain> secondBargains = secondBargainMapper.selectList( new QueryWrapper<SecondBargain>()
                .in("id",modelFileFileDTO.getSecondBargainId()));

        if("pay".equals(model.getModelType())){
            return payFile(model,secondBargains);
        }else if("deal".equals(model.getModelType())){
            return dealFile(model,secondBargains);
        }
//        else{
//            zipFile = createZipFile(filePaths, "XX.zip");
//        }
        return null;
    }

    private File dealFile(PModel model, List<SecondBargain> secondBargains) {

        List<String> filePaths = new ArrayList<>();

        String ftlName = UPLOAD_DIR + model.getUniqueFileName();
        for(SecondBargain s:secondBargains){
            File templateFile = new File(ftlName);
            try (XWPFDocument word = new XWPFDocument(Files.newInputStream(templateFile.toPath()))) {
                QueryWrapper<Choose> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", s.getOrderId());
                List<Choose> chooseAll = chooseMapper.selectList(queryWrapper);
                Project project = projectService.getById(chooseAll.get(0).getPid());
                // 准备参数
                Map<String, Object> params = prepareParamsDeal(chooseAll.get(0), project,s);
                // 替换段落中的占位符
                replaceText(word, params);

                // 在第一个表格中添加多行并填充数据
                if (!word.getTables().isEmpty()) {
                    XWPFTable table = word.getTables().get(0);
                    addDataToTable(table, params);
                }
                // 设置页眉页脚（如果需要）
                setHeadersFooters(word, params);

                // 保存Word文档到临时文件
                File tempFile = File.createTempFile("doc-", ".docx");
                try (FileOutputStream fos = new FileOutputStream(tempFile)) {
                    word.write(fos);
                    filePaths.add(tempFile.getAbsolutePath());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            File zipFile = null;
            zipFile = createZipFile(filePaths, "deal.zip");
            // 清理临时文件
            return zipFile;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 清理临时文件
            cleanUpTemporaryFiles(filePaths);
        }
        return null;
    }

    private Map<String, Object> prepareParamsDeal(Choose choose, Project project, SecondBargain s) {
        String institutions = project.getInstitutions();
        Agency agency = agencyMapper.selectOne(new QueryWrapper<Agency>().eq("agency",institutions));

        String strDateFormat = "yyyy-MM-dd";
        Map<String, Object> params = new HashMap<>();
        params.put("code",choose.getSubcontract()+"-"+choose.getPackageName()+"-"+choose.getOrdersNumber());

        params.put("companyName", choose.getCompanyName());
        params.put("projectName", project.getName());
        params.put("infoNumber", project.getInfoNumber());
        params.put("sPackage", choose.getSubcontract()+choose.getPackageName());

        params.put("projectUnit", choose.getDemandUnit());
        params.put("name", choose.getProjectName());
        params.put("quantity", choose.getPrice());
        params.put("finalUnitPrice", s.getAmount());

        params.put("personName", choose.getPersonName());
        params.put("personTelephone", choose.getPersonTelephone());
        params.put("contacts", choose.getContacts());
        params.put("contactInformation", choose.getContactInformation());

        params.put("procurementPeople", project.getProcurementPeople());
        params.put("institutions", agency.getAgency());
        params.put("date", DateFormatUtils.format(new Date(), strDateFormat));


        return params;
    }

    public File payFile(PModel model ,List<SecondBargain> secondBargains){
        List<String> filePaths = new ArrayList<>();
        String ftlName = UPLOAD_DIR + model.getUniqueFileName();
        for(SecondBargain s:secondBargains){
            File templateFile = new File(ftlName);
            try (XWPFDocument word = new XWPFDocument(Files.newInputStream(templateFile.toPath()))) {
                QueryWrapper<Choose> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", s.getOrderId());
                List<Choose> chooseAll = chooseMapper.selectList(queryWrapper);
                Project project = projectService.getById(chooseAll.get(0).getPid());
                // 准备参数
                Map<String, Object> params = prepareParamsPay(chooseAll.get(0), project,s);
                // 替换段落中的占位符
                replaceText(word, params);

                // 在第一个表格中添加多行并填充数据
                if (!word.getTables().isEmpty()) {
                    XWPFTable table = word.getTables().get(0);
                    addDataToTable(table, params);
                }
                // 设置页眉页脚（如果需要）
                setHeadersFooters(word, params);

                // 保存Word文档到临时文件
                File tempFile = File.createTempFile("doc-", ".docx");
                try (FileOutputStream fos = new FileOutputStream(tempFile)) {
                    word.write(fos);
                    filePaths.add(tempFile.getAbsolutePath());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            File zipFile = null;

            zipFile = createZipFile(filePaths, "pay.zip");
//            // 创建压缩包
//            if("pay".equals(model.getModelType())){
//
//            }else if("deal".equals(model.getModelType())){
//                zipFile = createZipFile(filePaths, "deal.zip");
//            }else{
//                zipFile = createZipFile(filePaths, "XX.zip");
//            }
            // 清理临时文件
            return zipFile;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 清理临时文件
            cleanUpTemporaryFiles(filePaths);
        }
        return null;
    }
    private  Map<String, Object> prepareParamsPay(Choose choose, Project project,SecondBargain s) {
        String institutions = project.getInstitutions();
        Agency agency = agencyMapper.selectOne(new QueryWrapper<Agency>().eq("agency",institutions));

        String strDateFormat = "yyyy-MM-dd";
        Map<String, Object> params = new HashMap<>();
        params.put("companyName", choose.getCompanyName());
        params.put("projectName", project.getName());
        params.put("agency", agency.getAgency());
        params.put("openBank", agency.getOpenBank());
        params.put("account", agency.getAccount());
        params.put("infoNumber", project.getInfoNumber());
        params.put("amount", s.getAmount());
        params.put("charge", s.getCharge());
        params.put("name", choose.getProjectName());
        params.put("date", DateFormatUtils.format(new Date(), strDateFormat));
        return params;
    }

    private static void addDataToTable(XWPFTable table, Map<String, Object> params) {
        // 遍历参数映射进行静态文本替换
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String placeholder = entry.getKey();
            Object replacement = entry.getValue();
            if (replacement instanceof List<?>) {// 如果是列表，则处理动态数据
                if(ObjectUtil.isNotEmpty(replacement)){
                    handleDynamicData(table, placeholder, (List<?>) replacement);
                }
            } else {
                if(ObjectUtil.isNotEmpty(replacement)){
                    // 否则进行简单的文本替换
                    simpleReplace(table, placeholder, replacement.toString());
                }else{
                    simpleReplace(table, placeholder, "");
                }

            }
        }
    }
    private static void simpleReplace(XWPFTable table, String placeholder, String replacement) {
        // 遍历表格的所有行
        for (XWPFTableRow row : table.getRows()) {
            // 遍历行中的所有单元格
            for (XWPFTableCell cell : row.getTableCells()) {
                // 遍历单元格中的所有段落
                for (XWPFParagraph paragraph : cell.getParagraphs()) {
                    // 遍历段落中的所有运行元素
                    for (XWPFRun run : paragraph.getRuns()) {
                        String text = run.getText(0);
                        if (text != null && !text.trim().isEmpty() && text.contains(placeholder)) {
                            // 替换文本
                            text = text.replace(placeholder, replacement);
                            run.setText(text, 0);
                        }
                    }
                }
            }
        }
    }
    private static void handleDynamicData(XWPFTable table, String placeholder, List<?> dataList) {
        int templateRowIndex = -1; // 模板行索引，假设第一行为标题行，第二行为模板行

        // 查找包含占位符的模板行
        for (int i = 3; i < table.getRows().size(); i++) {
            XWPFTableRow row = table.getRow(i);
            boolean containsPlaceholder = false;
            for (XWPFTableCell cell : row.getTableCells()) {
                for (XWPFParagraph paragraph : cell.getParagraphs()) {
                    for (XWPFRun run : paragraph.getRuns()) {
                        String text = run.getText(0);
                        if (text != null && text.contains(placeholder)) {
                            containsPlaceholder = true;
                            break;
                        }
                    }
                    if (containsPlaceholder) {
                        break;
                    }
                }
                if (containsPlaceholder) {
                    break;
                }
            }
            if (containsPlaceholder) {
                templateRowIndex = i;
                break;
            }
        }

        if (templateRowIndex >= 0) {
            int modelRow = templateRowIndex;
            // 复制模板行并填充数据
            for (Object dataItem : dataList) {
                if (dataItem instanceof Map) {
                    @SuppressWarnings("unchecked")
                    Map<String, String> dataMap = (Map<String, String>) dataItem;
                    XWPFTableRow newRow = table.insertNewTableRow(++templateRowIndex);
                    // 复制模板行到新行
                    copyRow(table.getRow(modelRow), newRow);
                    // 填充新行的数据
                    populateRow(newRow, dataMap);
                }
            }
            // 删除模板行
            table.removeRow(modelRow);
        }
    }

    private static void copyRow(XWPFTableRow source, XWPFTableRow dest) {
        for (int i = 0; i < source.getTableCells().size(); i++) {
            XWPFTableCell sourceCell = source.getCell(i);
            XWPFTableCell destCell = dest.createCell();
            for (XWPFParagraph p : sourceCell.getParagraphs()) {
                XWPFParagraph newP = destCell.addParagraph();
                for (XWPFRun r : p.getRuns()) {
                    XWPFRun newR = newP.createRun();
                    newR.setText(r.getText(0));
                    // 可以复制更多属性，例如字体、颜色等
                }
            }
        }
    }

    private static void populateRow(XWPFTableRow row, Map<String, String> dataMap) {
        for (XWPFTableCell cell : row.getTableCells()) {
            for (XWPFParagraph paragraph : cell.getParagraphs()) {
                for (XWPFRun run : paragraph.getRuns()) {
                    String text = run.getText(0);
                    if (text != null) {
                        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
                            String key =  entry.getKey();
                            if (text.contains(key)) {
                                text = text.replace(key, entry.getValue());
                                run.setText(text, 0);
                            }
                        }
                    }
                }
            }
        }
    }

    private static void replaceText(XWPFDocument document, Map<String, Object> params) {
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    if (text != null && text.contains(entry.getKey())) {
                        run.setText(text.replaceAll(entry.getKey(), entry.getValue().toString()), 0);
                    }
                }
            }
        }
    }

    private static void setHeadersFooters(XWPFDocument document, Map<String, Object> params) {
        List<XWPFFooter> footerList = document.getFooterList();
        for (XWPFFooter footer : footerList) {
            for (XWPFParagraph paragraph : footer.getParagraphs()) {
                for (XWPFRun run : paragraph.getRuns()) {
                    String text = run.getText(0);
                    for (Map.Entry<String, Object> entry : params.entrySet()) {
                        if (text != null && text.contains(entry.getKey())) {
                            run.setText(text.replaceAll(entry.getKey(), entry.getValue().toString()), 0);
                        }
                    }
                }
            }
        }
    }

    private File createZipFile(List<String> filePaths, String zipFileName) throws IOException {
        File zipFile = new File(zipFileName);
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
            for (String filePath : filePaths) {
                File fileToZip = new File(filePath);
                try (FileInputStream fis = new FileInputStream(fileToZip)) {
                    ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
                    zos.putNextEntry(zipEntry);
                    byte[] bytes = new byte[1024];
                    int length;
                    while ((length = fis.read(bytes)) >= 0) {
                        zos.write(bytes, 0, length);
                    }
                    zos.closeEntry();
                }
            }
        }
        return zipFile;
    }

    private static void cleanUpTemporaryFiles(List<String> filePaths) {
        for (String filePath : filePaths) {
            File tempFile = new File(filePath);
            if (tempFile.exists() && !tempFile.delete()) {
                System.out.println("Failed to delete temporary file: " + filePath);
            }
        }
    }
}
